﻿using PARK.Common.Core.Manager;
using PARK.Common.Enum;
using PARK.Common.Extension;
using PARK.Common.Filter;
using PARK.Dependency;
using PARK.DynamicApiController;
using PARK.FriendlyException;
using Mapster;
using Microsoft.AspNetCore.Mvc;
using SqlSugar;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Yitter.IdGenerator;
using PARK.Common.Helper;
using PARK.JsonSerialization;
using PARK.System.Interfaces.Permission;
using PARK.Common.Util;
using PARK.Attend.Interfaces.AttendRecord;
using PARK.Attend.Entitys;
using PARK.Accessctl.Entitys.Dto.AccessRecord;
using PARK.Accessctl.Entitys;
using PARK.ClayObject;
using PARK.Common.Model.NPOI;
using PARK.Common.Configuration;
using PARK.DataEncryption;
using PARK.CardAcct.Entitys;
using PARK.Attend.Entitys.Dto.AttendReport;
using PARK.Attend.Entitys.Entity;
using System.Data;
using PARK.Attend.Entitys.Dto.AttendRecord;
using System.Dynamic;
using PARK.Common.Helper.NewNPOI;
using System.Globalization;

namespace PARK.Attend.AttendRecord
{
    /// <summary>
    /// 考勤记录服务
    /// </summary>
    [ApiDescriptionSettings(Tag = "Attend", Name = "Record", Order = 200)]
    [Route("api/attend/[controller]")]
    public class AttendRecordService : IAttendRecordService, IDynamicApiController, ITransient
    {
        private readonly ISqlSugarRepository<AttendRecordEntity> _attendRecordRepository;
        private readonly SqlSugarScope _db;
        private readonly IUserManager _userManager;
        private readonly IOrganizeService _organizeService; // 机构表仓储

        /// <summary>
        /// 初始化一个<see cref="AttendRecordService"/>类型的新实例
        /// </summary>
        public AttendRecordService(
            ISqlSugarRepository<AttendRecordEntity> attendRecordRepository,
            IUserManager userManager,
             IOrganizeService organizeService)
        {
            _attendRecordRepository = attendRecordRepository;
            _db = _attendRecordRepository.Context;
            _userManager = userManager;
            _organizeService = organizeService;
        }

        /// <summary>
        /// 获取考勤记录
        /// </summary>
        /// <param name="id">参数</param>
        /// <returns></returns>
        [HttpGet("{id}")]
        public async Task<dynamic> GetInfo(string id)
        {
            var entity = await _db.Queryable<AttendRecordEntity>().FirstAsync(p => p.Id == id);
            var output = entity.Adapt<AttendRecordInfoOutput>();
            return output;
        }

        /// <summary>
		/// 获取考勤记录列表
		/// </summary>
		/// <param name="input">请求参数</param>
		/// <returns></returns>
        [HttpGet("")]
        public async Task<dynamic> GetList([FromQuery] AttendRecordListQueryInput input)
        {
            var userInfo = await _userManager.GetUserInfo();
            if (userInfo != null && userInfo.UserAdminFlag != 2 && !string.IsNullOrEmpty(userInfo.companyId))
            {
                //打卡日期
                List<string> queryBillDate = input.passtime != null ? input.passtime.Split(',').ToObeject<List<string>>() : null;
                DateTime? startBilldate = queryBillDate != null ? Ext.GetDateTime(queryBillDate.First()) : null;
                DateTime? endBilldate = queryBillDate != null ? Ext.GetDateTime(queryBillDate.Last()) : null;
                var Pars = new List<SugarParameter>(){
                                        new SugarParameter("@DepartId",input.organizeId),
                                        new SugarParameter("@begDate",Convert.ToDateTime(startBilldate).ToString("yyyy-MM-dd")),
                                        new SugarParameter("@endDate",Convert.ToDateTime(endBilldate).ToString("yyyy-MM-dd")),
                                        new SugarParameter("@ctlId",input.ctlId),
                                        new SugarParameter("@keyword",input.keyword),
                                        new SugarParameter("@CompanyId",userInfo.companyId)
                                    };
                var data = await _db.Ado.UseStoredProcedure().GetDataTableAsync("P_Get_AttendRecord", Pars);
                var heads = new List<string>();
                foreach (DataColumn item in data.Columns)
                {
                    if (item.ColumnName != "ReallName" && item.ColumnName != "JobNo" && item.ColumnName != "DepartName" && item.ColumnName != "EmployeeId")
                    {
                        heads.Add(item.ColumnName);
                    }
                }
                var jsonData = new
                {
                    list = data,
                    heads = heads
                };
                return JsonHelper.ToJson(jsonData);
            }
            else
                return null;
        }

        /// <summary>
        /// 新建考勤记录列表
        /// </summary>
        /// <param name="input">参数</param>
        /// <returns></returns>
        [HttpPost("")]
        public async Task Create([FromBody] AttendRecordCrInput input)
        {
            var check = await _db.Queryable<AttendRecordEntity>().FirstAsync(p => p.EmployeeId == input.EmployeeId && p.SignType == input.SignType && Convert.ToDateTime(p.SignTime).ToString("yyyy-MM-dd") == Convert.ToDateTime(input.SignTime).ToString("yyyy-MM-dd"));
            if (check != null)
            {
                throw PARKException.Bah("当前员工已打卡");
            }
            try
            {
                var userInfo = await _userManager.GetUserInfo();
                
                var entity = input.Adapt<AttendRecordEntity>();
                var assId = YitIdHelper.NextId().ToString();
                var employeeEntity = await _db.Queryable<EmployeeEntity>().FirstAsync(p => p.EmployeeId == input.EmployeeId);
                var rule = await _db.Queryable<AttendRuleEntity>().FirstAsync(p => p.CompanyId == userInfo.companyId);
                var specialdate = await _db.Queryable<SpecialDateEntity>()
                    .Where(p => Convert.ToDateTime(p.begspdate).ToString("yyyy-MM-dd") == Convert.ToDateTime(input.SignTime).ToString("yyyy-MM-dd"))
                    .FirstAsync(p => p.CompanyId == userInfo.companyId);
                //门禁
                if (input.ctlId != null)
                {
                    DateTime dateTime = Convert.ToDateTime(input.SignTime);
                    TimeSpan timeOfDay = dateTime.TimeOfDay; // 实到时间
                    TimeSpan result = new TimeSpan(); //应到时间

                    var accessCtlentity = await _db.Queryable<AccessCtlEntity>().FirstAsync(p => p.CtlId == input.ctlId);
                    entity.ctlId = input.ctlId;
                    entity.ctlSn = accessCtlentity.CtlSn;
                    entity.ctlName = accessCtlentity.CtlName;
                    entity.JobNo = employeeEntity.JobNum;
                    entity.ReallName = employeeEntity.RealName;
                    entity.CardNo = employeeEntity.CardNo;
                    entity.DepartId = employeeEntity.DepartId;
                    entity.DepartName = employeeEntity.DepartName;
                    entity.SignMint = 0;
                    entity.SignStatus = 1;
                    // 打卡类型 打卡状态
                    if (input.SignType == 1)
                    {
                        if (DateTime.TryParseExact(rule.goworkdate, "HH:mm:ss", CultureInfo.InvariantCulture, DateTimeStyles.None, out var date))
                        {
                            result = new TimeSpan(date.Hour, date.Minute, date.Second);
                        }
                        if (timeOfDay>result)
                        {
                            // 计算两个时间之间的差值
                            TimeSpan difference = timeOfDay - result;
                            // 获取分钟数
                            int minutes = difference.Minutes;
                            entity.SignMint = minutes;
                            entity.SignStatus = 2;
                        }
                    }
                    else
                    {
                        if (DateTime.TryParseExact(rule.offworkdate, "HH:mm:ss", CultureInfo.InvariantCulture, DateTimeStyles.None, out var date))
                        {
                            result = new TimeSpan(date.Hour, date.Minute, date.Second);
                        }
                        if (timeOfDay < result)
                        {
                            // 计算两个时间之间的差值
                            TimeSpan difference = result - timeOfDay;
                            // 获取分钟数
                            int minutes = difference.Minutes;
                            entity.SignMint = minutes;
                            entity.SignStatus = 3;
                        }
                    }
                    // 工作 休息
                    entity.worktype = 1;
                    if (specialdate != null)
                    {
                        entity.worktype = specialdate.worktype;
                    }
                    else
                    {
                        entity.worktype = GetWeekNow(Convert.ToDateTime(input.SignTime));
                    }
                    entity.accessreId = assId;
                    entity.CompanyId = userInfo.companyId;
                    entity.CompanyName = userInfo.companyName;
                    entity.Id = YitIdHelper.NextId().ToString();
                    entity.Description = "手工录入";
                    entity.DataSoure = 1;
                    entity.Create();
                    await _db.Insertable(entity).IgnoreColumns(ignoreNullColumn: true).ExecuteCommandAsync();

                    //写入开门记录
                    AccessRecordEntity accessRecordEntity = new AccessRecordEntity();
                    accessRecordEntity.CtlId = entity.ctlId;
                    accessRecordEntity.CtlSn = accessCtlentity.CtlSn;
                    accessRecordEntity.ctlName = accessCtlentity.CtlName;
                    accessRecordEntity.CtlInex = "";
                    accessRecordEntity.Ctlposition = accessCtlentity.Ctlposition;
                    accessRecordEntity.InOrout = 1;
                    accessRecordEntity.InOroutName = "进门";
                    accessRecordEntity.IsAtt = 1;
                    accessRecordEntity.IsToAtt = 1;
                    accessRecordEntity.ReallName = entity.ReallName;
                    accessRecordEntity.JobNo = entity.JobNo;
                    accessRecordEntity.CardNo = entity.CardNo;
                    accessRecordEntity.PassStatus = 1;
                    accessRecordEntity.PassStatusName = "通过";
                    accessRecordEntity.Passtime = Convert.ToDateTime(entity.SignTime);
                    accessRecordEntity.EmployeeId = entity.EmployeeId;
                    accessRecordEntity.DoorAreaId = accessCtlentity.DoorAreaId;
                    accessRecordEntity.DoorAreaName = accessCtlentity.DoorAreaName;
                    accessRecordEntity.DepartId = entity.DepartId;
                    accessRecordEntity.DepartName = entity.DepartName;
                    accessRecordEntity.CompanyId = userInfo.companyId;
                    accessRecordEntity.CompanyName = userInfo.companyName;
                    accessRecordEntity.Description = "刷卡进门";
                    accessRecordEntity.CatCardNo = employeeEntity.CatCardNo;
                    accessRecordEntity.Ctlposition = accessCtlentity.Ctlposition;
                    accessRecordEntity.Id = assId;
                    accessRecordEntity.DoorNo = "1";
                    var ctlauthentity = _db.Queryable<AccessDoorEntity>().Where(p => p.CtlId == input.ctlId && p.DoorNo == 1 && p.CompanyId == userInfo.companyId).ToList();
                    if (ctlauthentity.Count > 0)
                    {
                        accessRecordEntity.DoorId = ctlauthentity[0].DoorId;
                        accessRecordEntity.DoorName = ctlauthentity[0].DoorName;
                    }
                    await _db.Insertable(accessRecordEntity).IgnoreColumns(ignoreNullColumn: true).ExecuteCommandAsync();
                    var Pars = new List<SugarParameter>(){
                                        new SugarParameter("@recordId",entity.Id),
                                    };
                    _db.Ado.UseStoredProcedure().ExecuteCommand("P_Attend_report_Add", Pars);
                }
            }
            catch (Exception ex)
            {
                throw PARKException.Oh(ErrorCode.COM1003);
            }

        }

        /// <summary>
        /// 下属机构
        /// </summary>
        /// <param name="organizeId">机构ID</param>
        /// <returns></returns>
        [NonAction]
        public async Task<List<string>> GetSubOrganizeIds(string organizeId)
        {
            var data = await _organizeService.GetListAsync();
            data = data.TreeChildNode(organizeId, t => t.Id, t => t.ParentId);
            return data.Select(m => m.Id).ToList();
        }

        /// <summary>
        /// 更新考勤记录
        /// </summary>
        /// <param name="id">主键</param>
        /// <param name="input">参数</param>
        /// <returns></returns>
        [HttpPut("{id}")]
        public async Task Update(string id, [FromBody] AttendRecordUpInput input)
        {
            var entity = input.Adapt<AttendRecordEntity>();
            var isOk = await _db.Updateable(entity).IgnoreColumns(ignoreAllNullColumns: true).ExecuteCommandAsync();
            if (!(isOk > 0)) throw PARKException.Oh(ErrorCode.COM1001);
        }

        /// <summary>
        /// 删除考勤记录
        /// </summary>
        /// <returns></returns>
        [HttpDelete("{id}")]
        public async Task Delete(string id)
        {
            var entity = await _db.Queryable<AttendRecordEntity>().FirstAsync(p => p.Id == id);
            _ = entity ?? throw PARKException.Oh(ErrorCode.COM1005);
            var isOk = await _db.Deleteable<AttendRecordEntity>().Where(d => d.Id == id).ExecuteCommandAsync();
            if (!(isOk > 0)) throw PARKException.Oh(ErrorCode.COM1002);
        }

        /// <summary>
        /// 是否提供新增考勤记录功能
        /// </summary>
        /// <returns></returns>
        [HttpGet("GetAddAuthorware")]
        public async Task<dynamic> GetAddAuthorware()
        {
            var userInfo = await _userManager.GetUserInfo();
            if (userInfo != null && userInfo.UserAdminFlag == 1)
            {
                return new { auth = 1 };
            }
            else
            {
                return new { auth = 0 };
            }
        }

        #region 导出考勤记录Excel
        /// <summary>
        /// 获取考勤记录无分页列表
        /// </summary>
        /// <param name="input">请求参数</param>
        /// <returns></returns>
        [NonAction]
        public async Task<DataTable> GetNoPagingList([FromQuery] AttendRecordListQueryInput input)
        {
            var userInfo = await _userManager.GetUserInfo();
            if (userInfo != null && userInfo.UserAdminFlag != 2 && !string.IsNullOrEmpty(userInfo.companyId))
            {
                //打卡日期
                List<string> queryBillDate = input.passtime != null ? input.passtime.Split(',').ToObeject<List<string>>() : null;
                DateTime? startBilldate = queryBillDate != null ? Ext.GetDateTime(queryBillDate.First()) : null;
                DateTime? endBilldate = queryBillDate != null ? Ext.GetDateTime(queryBillDate.Last()) : null;
                var Pars = new List<SugarParameter>(){
                                        new SugarParameter("@DepartId",input.organizeId),
                                        new SugarParameter("@begDate",Convert.ToDateTime(startBilldate).ToString("yyyy-MM-dd")),
                                        new SugarParameter("@endDate",Convert.ToDateTime(endBilldate).ToString("yyyy-MM-dd")),
                                        new SugarParameter("@keyword",input.keyword),
                                        new SugarParameter("@CompanyId",userInfo.companyId)
                                    };
                var data = await _db.Ado.UseStoredProcedure().GetDataTableAsync("P_Get_AttendRecord", Pars);
                return data;
            }
            else
                return null;

        }

        /// <summary>
        /// 导出发放记录
        /// </summary>
        /// <param name="input">请求参数</param>
        /// <returns></returns>
        [HttpGet("Actions/Export")]
        public async Task<dynamic> Export([FromQuery] AttendRecordListQueryInput input)
        {
            var exportData = await this.GetNoPagingList(input);
            exportData.Columns.RemoveAt(0);
            //打卡日期
            List<string> queryBillDate = input.passtime != null ? input.passtime.Split(',').ToObeject<List<string>>() : null;
            DateTime startBilldate = Ext.GetDateTime(queryBillDate.First());
            DateTime endBilldate = Ext.GetDateTime(queryBillDate.Last());
            var FileName = "考勤记录";

            var columnId = "";
            var columnName = "";
            for (int j = 0; j < exportData.Columns.Count; j++)
            {
                columnId += exportData.Columns[j].ColumnName.ToString() + ";";
                if (exportData.Columns[j].ColumnName.ToString() == "DepartName")
                {
                    columnName += "部门" + "#";
                }
                else if (exportData.Columns[j].ColumnName.ToString() == "JobNo")
                {
                    columnName += "工号" + "#";
                }
                else if (exportData.Columns[j].ColumnName.ToString() == "ReallName")
                {
                    columnName += "姓名" + "#";
                }
                else
                {
                    columnName += exportData.Columns[j].ColumnName.ToString() + "#";
                }
            }
            if (!string.IsNullOrEmpty(columnId) && columnId.Length > 0)
            {
                columnId = columnId.Substring(0, columnId.Length - 1);
            }
            if (!string.IsNullOrEmpty(columnName) && columnName.Length > 0)
            {
                columnName = columnName.Substring(0, columnName.Length - 1);
            }
            var _FileName = FileName + "_" + startBilldate.ToString("yyyy-MM-dd") + "_" + endBilldate.ToString("yyyy-MM-dd") + ".xls";
            var addPath = FileVariable.TemporaryFilePath + _FileName;
            IList<NPOIModel> list = new List<NPOIModel>();
            list.Add(new NPOIModel(exportData, columnId, _FileName, columnName, _FileName));
            NPOIHelper.Export(_FileName, list, 2, addPath);
            var fileName = _userManager.UserId + "|" + addPath + "|xls";
            var output = new
            {
                name = FileName,
                //url = "wwwroot/Resources/TemporaryFile/" + excelconfig.FileName
                url = "api/file/Download?encryption=" + DESCEncryption.Encrypt(fileName, "JNPF") //"wwwroot/Template/TemporaryFile/" + excelconfig.FileName //
            };
            return output;
        }
        #endregion


        #region 重新计算考勤记录考勤报表
        [HttpGet("AgainSum")]
        public async Task AgainSum([FromQuery] string querytime)
        {
            try
            {
                if (!string.IsNullOrEmpty(querytime))
                {
                    var userInfo = await _userManager.GetUserInfo();
                    await _db.Deleteable<AttendRecordEntity>().Where(p => p.CompanyId == userInfo.companyId && Convert.ToDateTime(p.SignTime).ToString("yyyy-MM-dd") == querytime).ExecuteCommandAsync();
                    await _db.Deleteable<AttendReportEntity>().Where(p => p.CompanyId == userInfo.companyId)
                        .Where(p => Convert.ToDateTime(p.upSignTime).ToString("yyyy-MM-dd") == querytime || Convert.ToDateTime(p.offSignTime).ToString("yyyy-MM-dd") == querytime)
                        .ExecuteCommandAsync();
                    //await _db.Ado.ExecuteCommandAsync("delete from attend_records where CompanyId='"+userInfo.companyId+ "' and CONVERT(VARCHAR(10),SignTime,23)='CONVERT(VARCHAR(10)," + querytime + ",23)");
                    //await _db.Ado.ExecuteCommandAsync("delete from attend_report where CompanyId='" + userInfo.companyId+ "' and (CONVERT(VARCHAR(10),upSignTime,23)='CONVERT(VARCHAR(10)," + querytime + ",23) or (CONVERT(VARCHAR(10),offSignTime,23)='CONVERT(VARCHAR(10)," + querytime + ",23))");
                    var Pars = new List<SugarParameter>(){
                                        new SugarParameter("@querytime",querytime),
                                        new SugarParameter("@CompanyId",userInfo.companyId.ToString())
                                    };
                    _db.Ado.UseStoredProcedure().ExecuteCommand("P_Attend_records_Add", Pars);
                }
            }
            catch (Exception ex)
            {
                throw PARKException.Oh(ErrorCode.COM1003);
            }

        }
        #endregion

        #region 判断日期是否工作日
        private int GetWeekNow(DateTime date)
        {
            string strWeek = date.DayOfWeek.ToString();
            switch (strWeek)
            {
                case "Monday":
                case "Tuesday":
                case "Wednesday":
                case "Thursday":
                case "Friday":
                    return 1;
                case "Saturday":
                case "Sunday":
                    return 0;
            }
            return 1;
        }
        #endregion
    }
}
